﻿using MySql.Data.MySqlClient;
using System;
using System.Data;
using System.IO;
using System.Text;
namespace ConsoleApp2
{
    public class EntityGenerator
    {
        private readonly string _connectionString;

        /// <summary>
        /// 初始化实体生成器
        /// </summary>
        /// <param name="connectionString">MySQL数据库连接字符串</param>
        public EntityGenerator(string connectionString)
        {
            _connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));
        }

        /// <summary>
        /// 根据表名生成实体类文件
        /// </summary>
        /// <param name="tableName">要生成实体类的数据库表名</param>
        /// <param name="outputDirectory">实体类文件输出的目录</param>
        /// <param name="namespaceName">实体类所属的命名空间（可选）</param>
        public void GenerateEntityClass(string tableName, string outputDirectory, string namespaceName = null)
        {
            if (string.IsNullOrWhiteSpace(tableName))
            {
                throw new ArgumentNullException(nameof(tableName));
            }
            if (string.IsNullOrWhiteSpace(outputDirectory))
            {
                throw new ArgumentNullException(nameof(outputDirectory));
            }

            // 确保输出目录存在
            if (!Directory.Exists(outputDirectory))
            {
                Directory.CreateDirectory(outputDirectory);
            }

            // 查询表结构
            DataTable tableSchema = GetTableSchema(tableName);

            // 生成实体类代码
            string entityClassCode = BuildEntityClassCode(tableName, tableSchema, namespaceName);

            // 写入文件
            string fileName = $"{tableName}.cs";
            string filePath = Path.Combine(outputDirectory, fileName);
            File.WriteAllText(filePath, entityClassCode, Encoding.UTF8);

            Console.WriteLine($"Successfully generated entity class for table '{tableName}' at: {filePath}");
        }

        /// <summary>
        /// 获取指定表的数据库表结构信息
        /// </summary>
        private DataTable GetTableSchema(string tableName)
        {
            DataTable schemaTable = new DataTable();
            using (MySqlConnection connection = new MySqlConnection(_connectionString))
            {
                connection.Open();
                // 使用 INFORMATION_SCHEMA.COLUMNS 查询表结构，包括列名和数据类型
                string query = $"SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = @tableName";

                using (MySqlCommand command = new MySqlCommand(query, connection))
                {
                    command.Parameters.AddWithValue("@tableName", tableName);
                    using (MySqlDataAdapter adapter = new MySqlDataAdapter(command))
                    {
                        adapter.Fill(schemaTable);
                    }
                }
            }
            return schemaTable;
        }

        /// <summary>
        /// 根据表结构构建实体类 C# 代码字符串
        /// </summary>
        private string BuildEntityClassCode(string tableName, DataTable tableSchema, string namespaceName)
        {
            StringBuilder codeBuilder = new StringBuilder();

            // 添加文件头注释
            codeBuilder.AppendLine($"// Auto-generated by EntityGenerator.cs");
            codeBuilder.AppendLine($"// Generated on: {DateTime.Now}");
            codeBuilder.AppendLine();

            // 添加命名空间（如果提供）
            if (!string.IsNullOrWhiteSpace(namespaceName))
            {
                codeBuilder.AppendLine($"namespace {namespaceName}");
                codeBuilder.AppendLine("{");
                codeBuilder.AppendLine();
            }

            // 添加类定义
            // 将表名转换为 PascalCase (首字母大写)
            string className = ToPascalCase(tableName);
            codeBuilder.AppendLine($"public class {className}");
            codeBuilder.AppendLine("{");

            // 遍历表结构，生成属性
            foreach (DataRow row in tableSchema.Rows)
            {
                string columnName = row["COLUMN_NAME"].ToString();
                string dataType = row["DATA_TYPE"].ToString();
                bool isNullable = row["IS_NULLABLE"].ToString().ToUpper() == "YES";

                // 转换为 C# 数据类型
                string csharpType = ConvertMySqlDataTypeToCSharp(dataType, isNullable);

                // 将列名转换为 PascalCase (首字母大写)
                string propertyName = ToPascalCase(columnName);

                // 添加属性定义
                // 添加属性的 XML 注释（可选）
                codeBuilder.AppendLine($"    /// <summary>");
                codeBuilder.AppendLine($"    /// 获取或设置 {propertyName} ({dataType})");
                codeBuilder.AppendLine($"    /// </summary>");
                codeBuilder.AppendLine($"    public {csharpType} {propertyName} {{ get; set; }}");
                codeBuilder.AppendLine();
            }

            // 闭合类定义
            codeBuilder.AppendLine("}");

            // 闭合命名空间（如果提供）
            if (!string.IsNullOrWhiteSpace(namespaceName))
            {
                codeBuilder.AppendLine("}");
            }

            return codeBuilder.ToString();
        }

        /// <summary>
        /// 将 MySQL 数据类型转换为 C# 数据类型
        /// </summary>
        private string ConvertMySqlDataTypeToCSharp(string mySqlDataType, bool isNullable)
        {
            string csharpType;
            switch (mySqlDataType.ToLower())
            {
                case "int":
                case "integer":
                case "tinyint":
                case "smallint":
                case "mediumint":
                    csharpType = isNullable ? "int?" : "int";
                    break;
                case "bigint":
                    csharpType = isNullable ? "long?" : "long";
                    break;
                case "float":
                    csharpType = isNullable ? "float?" : "float";
                    break;
                case "double":
                case "real":
                case "decimal":
                case "numeric":
                    csharpType = isNullable ? "decimal?" : "decimal";
                    break;
                case "bit":
                    csharpType = isNullable ? "bool?" : "bool"; // BIT 类型在 .NET 中通常映射为 bool
                    break;
                case "date":
                case "datetime":
                case "timestamp":
                    csharpType = isNullable ? "DateTime?" : "DateTime";
                    break;
                case "time":
                    csharpType = isNullable ? "TimeSpan?" : "TimeSpan";
                    break;
                case "year":
                    csharpType = isNullable ? "short?" : "short"; // Year 通常可以用 short 表示
                    break;
                case "char":
                case "varchar":
                case "text":
                case "mediumtext":
                case "longtext":
                case "enum":
                case "set":
                    csharpType = "string"; // 即使是 nullABLE 的 char/varchar/text/enum/set 映射为 string，因为 string 本身是引用类型，可以为 null
                    break;
                case "binary":
                case "varbinary":
                case "blob":
                case "mediumblob":
                case "longblob":
                    csharpType = "byte[]";
                    break;
                case "json":
                    csharpType = "string"; // JSON 通常以字符串形式处理
                    break;
                case "double precision": // 可能是 double 的别名
                    csharpType = isNullable ? "double?" : "double";
                    break;
                case "boolean": // MySQL 8.0 后的 boolean 类型
                    csharpType = isNullable ? "bool?" : "bool";
                    break;
                // 可以在这里添加更多 MySQL 数据类型的映射
                default:
                    // 对于未知的类型，可以将其映射为 object 或 string，并添加警告
                    Console.WriteLine($"Warning: Unknown MySQL data type '{mySqlDataType}'. Mapping to string.");
                    csharpType = "string";
                    break;
            }

            // 如果字段本身可空, 且 C# 类型是值类型, 则在其后面添加 '?'
            if (isNullable && csharpType.EndsWith("?") == false && !csharpType.Contains("?"))
            {
                // 针对 string, byte[], object 等引用类型，不需要加 ?，因为它们本身就可以为 null
                if (csharpType != "string" && csharpType != "byte[]" && csharpType != "object")
                {
                    csharpType += "?";
                }
            }

            return csharpType;
        }

        /// <summary>
        /// 将字符串转换为 PascalCase (例如: user_name -> UserName)
        /// </summary>
        private string ToPascalCase(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return input;
            }

            // 替换下划线后的字符为大写
            string[] words = input.Split('_');
            StringBuilder pascalCaseBuilder = new StringBuilder();

            foreach (string word in words)
            {
                if (!string.IsNullOrEmpty(word))
                {
                    pascalCaseBuilder.Append(char.ToUpper(word[0]));
                    if (word.Length > 1)
                    {
                        pascalCaseBuilder.Append(word.Substring(1).ToLower());
                    }
                }
            }
            return pascalCaseBuilder.ToString();
        }


    }
}